package org.linlinjava.litemall.admin.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.linlinjava.litemall.admin.constant.LitemallAdminConstants;
import org.linlinjava.litemall.admin.dto.AdminStrategyCodeDTO;
import org.linlinjava.litemall.admin.dto.AdminStrategyExtenDTO;
import org.linlinjava.litemall.admin.vo.AdminCouponStrategyDetailVO;
import org.linlinjava.litemall.admin.vo.AdminRuleConfigCouponsVO;
import org.linlinjava.litemall.admin.vo.AdminStatisticsStrategysVO;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.util.AdminCouponDateUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AdminLumiereCouponStrategyService {

    private final LumiereCouponStrategyService lumiereCouponStrategyService;

    private final LumiereCouponService lumiereCouponService;

    private final LumierelLevelMemberService lumierelLevelMemberService;
    private final LumiereLevelMemberPointService lumiereLevelMemberPointService;
    private final LumierelLevelMemberService lumiereLevelMemberService;

    private final LumierePayMemberService lumierePayMemberService;
    private final LumierePayMemberUserService lumierePayMemberUserService;

    private final LitemallUserService litemallUserService;

    private final LumiereCouponUserService lumiereCouponUserService;

    private final LitemallOrderService litemallOrderService;

    private final LitemallGiftCardService litemallGiftCardService;

    private final LumiereCouponGrantLogService lumiereCouponGrantLogService;

    private final LitemallAdminService litemallAdminService;

    private final NoticeHelper noticeHelper;


    public ResponseUtil.Response couponStrategys(Integer limit, Integer page, Integer status, String name, Short bearing, Integer couponType) {
        IPage<LumiereCouponStrategy> strategysVOS = lumiereCouponStrategyService.selectJoinListPage(new Page<>(page,limit),LumiereCouponStrategy.class, new MPJLambdaWrapper<LumiereCouponStrategy>()
                .selectAll(LumiereCouponStrategy.class)
                .selectAs(LumiereCoupon::getPictureUrl, LumiereCouponStrategy::getPictureUrl)
                .selectAs(LumiereCoupon::getName, LumiereCouponStrategy::getCouponName)
                .leftJoin(LumiereCoupon.class, LumiereCoupon::getId, LumiereCouponStrategy::getCouponId)
                .eq(status != null, LumiereCouponStrategy::getStatus, status)
                .like(StrUtil.isNotBlank(name), LumiereCouponStrategy::getName, name)
                .eq(bearing != null, LumiereCouponStrategy::getLossBearing, bearing)
                .eq(couponType != null, LumiereCouponStrategy::getCouponType, couponType)
                .orderByDesc(LumiereCouponStrategy::getAddTime));
        return ResponseUtil.okPage(strategysVOS);
    }

    public ResponseUtil.Response statusStrategys(LumiereCouponStrategy strategy) {
        if (strategy.getStatus()) {
            if (lumiereCouponService.getById(strategy.getCouponId()).getStatus().equals(0)) {
                return ResponseUtil.fail(401, "优惠券未上架！");
            }
        }
        return lumiereCouponStrategyService.updateById(strategy) ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response editStrategys(LumiereCouponStrategy strategy) {
        return lumiereCouponStrategyService.updateById(strategy) ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response saveStrategys(LumiereCouponStrategy strategy) {
        strategy.setDeleted(false);
        strategy.setAddTime(LocalDateTime.now());
        strategy.setUpdateTime(LocalDateTime.now());
        strategy.setStatus(false);
        return lumiereCouponStrategyService.save(strategy) ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response removeStrategys(Long id) {
        boolean b = lumiereCouponStrategyService.removeById(id);
        return b ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response levelMemberStrategys() {
        return ResponseUtil.ok(lumierelLevelMemberService.list());
    }

    public ResponseUtil.Response payMemberStrategys() {
        return ResponseUtil.ok(lumierePayMemberService.list());
    }

    public ResponseUtil.Response grantStrategyExten(AdminStrategyExtenDTO strategyExtenDTO) {
        //判断发放类型
        switch (strategyExtenDTO.getIsAll()) {
            //所有会员
            case 0: isAll(strategyExtenDTO);break;
            //指定会员
            case 1: isUser(strategyExtenDTO);break;
            //等级会员
            case 2: isLevelMember(strategyExtenDTO);break;
            //付费会员
            case 3: isPayMember(strategyExtenDTO);break;
        }
        return ResponseUtil.ok();
    }

    //发放推广券
    private void pullCoupon(LumiereCouponStrategy couponStrategy, LitemallUser user,Integer number) {
        LumiereCoupon lumiereCoupon = lumiereCouponService.getById(couponStrategy.getCouponId());
        for (int i=0;i<number;i++){
            LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(couponStrategy);
            long nextId = IdUtil.getSnowflake(2, 2).nextId();
            //发放推广券
            LumiereCouponUser couponUser = LumiereCouponUser.builder()
                    .userId(user.getId())
                    .strategyId(couponStrategy.getId())
                    .couponId(couponStrategy.getCouponId())
                    .startTime(localDateTimes[0])
                    .endTime(localDateTimes[1])
                    .userName(user.getUsername())
                    .code(String.valueOf(nextId))
                    .addTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .deleted(false)
                    .build();
            lumiereCouponUserService.save(couponUser);
        }
        noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER, LitemallAdminConstants.ADMIN_COUPON_PROMOTION_USER_TITLE, String.format(LitemallAdminConstants.ADMIN_COUPON_PROMOTION_USER_NOTICEHELPER, couponStrategy.getName(),number), user.getId(), lumiereCoupon);

    }

    private void saveGrantLog(AdminStrategyExtenDTO strategyExtenDTO,List<String> aimNames ){
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.findByid(strategyExtenDTO.getId());
        LumiereCouponGrantLog grantLog = LumiereCouponGrantLog.builder()
                .strategyId(strategyExtenDTO.getId())
                .strategyName(couponStrategy.getName())
                .couponId(couponStrategy.getCouponId())
                .createId(strategyExtenDTO.getAdminId())
                .num(strategyExtenDTO.getNumbers())
                .cause(strategyExtenDTO.getRemarks())
                .aim(strategyExtenDTO.getIsAll())
                .aimName(aimNames)
                .addTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .deleted(false)
                .build();
        lumiereCouponGrantLogService.save(grantLog);
    }

    @Async
    public void isAll(AdminStrategyExtenDTO strategyExtenDTO) {
        //获取策略
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(strategyExtenDTO.getId());
        //获取所有的正常用户
        List<LitemallUser> litemallUsers = litemallUserService.list(Wrappers.lambdaQuery(LitemallUser.class)
                .eq(LitemallUser::getInnerAccount,0)
                .eq(LitemallUser::getStatus, 0)
                .eq(LitemallUser::getDeleted, 0));
        litemallUsers.stream().forEach(user -> pullCoupon(couponStrategy, user,strategyExtenDTO.getNumbers()));
        //记录发放
        saveGrantLog(strategyExtenDTO, Arrays.asList("allUser"));
    }

    private void isUser(AdminStrategyExtenDTO strategyExtenDTO) {
        //获取策略
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(strategyExtenDTO.getId());
        //获取发放对象名称
        List<String> userNames = new ArrayList(strategyExtenDTO.getUserIds().size());
        for (Integer userId : strategyExtenDTO.getUserIds()) {
            LitemallUser litemallUser = litemallUserService.findById(userId);
            if(ObjectUtil.isNotNull(litemallUser)&&litemallUser.getStatus()==0&&litemallUser.getDeleted()==false){
                //获取用户
                pullCoupon(couponStrategy, litemallUser,strategyExtenDTO.getNumbers());
                userNames.add(litemallUser.getUsername());
            }
        }
        //记录发放
        saveGrantLog(strategyExtenDTO,userNames);
    }

    private void isLevelMember(AdminStrategyExtenDTO strategyExtenDTO) {
        //获取策略
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(strategyExtenDTO.getId());

        List<LitemallUser> litemallUsers = litemallUserService.list(Wrappers.lambdaQuery(LitemallUser.class)
                .in(LitemallUser::getUserLevel, strategyExtenDTO.getLevelMemberType()));
        //获取发放对象名称
        List<String> userNames = CollUtil.newArrayList();
        //获取所有等级会员
        litemallUsers.forEach(user -> {
            //判断用户正常和会员正常
            if (user.getDeleted() == false && user.getStatus() == 0 ) {
                pullCoupon(couponStrategy,user,strategyExtenDTO.getNumbers());
                userNames.add(user.getUsername());
            }
        });
        //记录发放
        saveGrantLog(strategyExtenDTO,userNames);
    }
    private void isPayMember(AdminStrategyExtenDTO strategyExtenDTO){
        //获取策略
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(strategyExtenDTO.getId());
        //获取发放对象名称
        List<String> userNames = CollUtil.newArrayList();
        //获取所有付费会员
        List<LumierePayMemberUser> lumierePayMemberUsers = lumierePayMemberUserService.list(Wrappers.lambdaQuery(LumierePayMemberUser.class)
                .in(LumierePayMemberUser::getPayMemberId,strategyExtenDTO.getPayMemberType()));
        lumierePayMemberUsers.stream().forEach(lumierePayMemberUser -> {
            //获取用户
            LitemallUser user = litemallUserService.findById(lumierePayMemberUser.getUserId());
           if(user.getDeleted() == false && user.getStatus() == 0 &&lumierePayMemberUser.getDeleted() == false){
               pullCoupon(couponStrategy,user,strategyExtenDTO.getNumbers());
               userNames.add(user.getUsername());
           }
        });
        //记录发放
        saveGrantLog(strategyExtenDTO,userNames);
    }


    public ResponseUtil.Response detailsStrategys(Long id) {
        AdminCouponStrategyDetailVO strategyDetailVO = AdminCouponStrategyDetailVO.builder().build();
        LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.getById(id);
        BeanUtil.copyProperties(lumiereCouponStrategy, strategyDetailVO);
        strategyDetailVO.setStrategyName(lumiereCouponStrategy.getName());
        LumiereCoupon lumiereCoupon = lumiereCouponService.getById(lumiereCouponStrategy.getCouponId());
        strategyDetailVO.setCouponName(lumiereCoupon.getName());
        //领取数
        long count = lumiereCouponUserService.count(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .eq(LumiereCouponUser::getCouponId, lumiereCouponStrategy.getCouponId()));
        strategyDetailVO.setReceiveNum(count);
        return ResponseUtil.ok(strategyDetailVO);
    }

    public ResponseUtil.Response statisticsStrategys(Long id, String startTime, String endTime, Integer shopId) {
        AdminStatisticsStrategysVO statisticsStrategysVO = AdminStatisticsStrategysVO.builder().build();
        LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.getById(id);
        if(ObjectUtil.isNull(lumiereCouponStrategy)){
            return ResponseUtil.fail();
        }
        //领取数
        long receiveNum = lumiereCouponUserService.count(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .between(startTime != null && endTime != null, LumiereCouponUser::getAddTime, startTime, endTime)
                .eq(shopId != null, LumiereCouponUser::getShopId, shopId)
                .eq(LumiereCouponUser::getStrategyId, id));
        //使用数量
        long useNum = lumiereCouponUserService.count(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .between(startTime != null && endTime != null, LumiereCouponUser::getAddTime, startTime, endTime)
                .eq(shopId != null, LumiereCouponUser::getShopId, shopId)
                .eq(LumiereCouponUser::getStrategyId, id)
                .isNotNull(LumiereCouponUser::getUsedTime));
        //使用优惠券订单总额
        List<LumiereCouponUser> lumiereCouponUsers = lumiereCouponUserService.list(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .between(startTime != null && endTime != null, LumiereCouponUser::getAddTime, startTime, endTime)
                .eq(shopId != null, LumiereCouponUser::getShopId, shopId)
                .eq(LumiereCouponUser::getStrategyId, id)
                .isNotNull(LumiereCouponUser::getOrderId));
        BigDecimal orderSumMoney = new BigDecimal(0.00);
        BigDecimal discountsSumMoney = new BigDecimal(0.00);
        if (!lumiereCouponUsers.isEmpty()) {
            List<Integer> orderIds = lumiereCouponUsers.stream().map(lumiereCouponUser -> lumiereCouponUser.getOrderId()).collect(Collectors.toList());
            List<LitemallOrder> litemallOrders = litemallOrderService.listByIds(orderIds);
            litemallOrders.forEach(litemallOrder -> {
                //使用优惠券订单总额
                orderSumMoney.add(litemallOrder.getActualPrice());
                //总优惠金额
                discountsSumMoney.add(litemallOrder.getCouponPrice());
            });
        }
        statisticsStrategysVO.setReceiveNum(receiveNum);
        statisticsStrategysVO.setUseNum(useNum);
        statisticsStrategysVO.setOrderSumMoney(orderSumMoney);
        statisticsStrategysVO.setDiscountsSumMoney(discountsSumMoney);
        return ResponseUtil.ok(statisticsStrategysVO);
    }

    public ResponseUtil.Response usersStrategys(Long id,String userName, Boolean status, Integer limit, Integer page, String startTime, String endTime, Integer shopId) {
        IPage<LumiereCouponUser> lumiereCouponUsers = lumiereCouponUserService.page(new Page<>(page,limit),Wrappers.lambdaQuery(LumiereCouponUser.class)
                .eq(LumiereCouponUser::getStrategyId,id)
                .between(startTime != null && endTime != null, LumiereCouponUser::getAddTime, startTime, endTime)
                .eq(shopId != null, LumiereCouponUser::getShopId, shopId)
                .like(StrUtil.isNotBlank(userName), LumiereCouponUser::getUserName, userName)
                .isNotNull(status != null && status, LumiereCouponUser::getUsedTime)
                .isNull(status != null && status == false, LumiereCouponUser::getUsedTime)
                .orderByDesc(status != null && status == true, LumiereCouponUser::getUsedTime)
        );
        return ResponseUtil.okPage(lumiereCouponUsers);
    }

    public synchronized ResponseUtil.Response saveCodeStrategys(AdminStrategyCodeDTO strategyCodeDTO) {
        //获取策略
        LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.getById(strategyCodeDTO.getStrategyId());
        List<LumiereCouponUser> lumiereCouponUsers = new ArrayList<>(strategyCodeDTO.getCode().size());
        for (String code : strategyCodeDTO.getCode()) {
            LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(lumiereCouponStrategy);
            LumiereCouponUser couponUser = LumiereCouponUser.builder()
                    .strategyId(strategyCodeDTO.getStrategyId())
                    .couponId(lumiereCouponStrategy.getCouponId())
                    .startTime(localDateTimes[0])
                    .endTime(localDateTimes[1])
                    .code(code)
                    .addTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .deleted(false)
                    .build();
            lumiereCouponUsers.add(couponUser);
        }
        boolean saveBatch = lumiereCouponUserService.saveBatch(lumiereCouponUsers);
        return saveBatch ? ResponseUtil.ok("券码录入成功") : ResponseUtil.fail("券码录入失败");
    }

    public ResponseUtil.Response recycleStrategys(Integer limit, Integer page, String name) {
        IPage<LumiereCouponStrategy> lumiereCouponStrategies = lumiereCouponStrategyService.page(new Page<>(page,limit),Wrappers.lambdaQuery(LumiereCouponStrategy.class)
                .eq(StrUtil.isNotBlank(name), LumiereCouponStrategy::getName, name)
                .eq(LumiereCouponStrategy::getDeleted, 1)
        );
        return ResponseUtil.okPage(lumiereCouponStrategies);
    }


    public ResponseUtil.Response recycletrategys(Long id) {
        LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.getById(id);
        lumiereCouponStrategy.setDeleted(true);
        return lumiereCouponStrategyService.updateById(lumiereCouponStrategy) ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response recycleDelete(Long id) {
        return lumiereCouponStrategyService.recycleDelete(id) ? ResponseUtil.ok() : ResponseUtil.fail();
    }

    public ResponseUtil.Response giftsList() {
        return ResponseUtil.ok(litemallGiftCardService.list());
    }

    public ResponseUtil.Response ruleConfigCoupons() {
        List<AdminRuleConfigCouponsVO> adminRuleConfigCouponsVOS = lumiereCouponStrategyService.selectJoinList(AdminRuleConfigCouponsVO.class, new MPJLambdaWrapper<LumiereCouponStrategy>()
                .select(LumiereCouponStrategy::getId,
                        LumiereCouponStrategy::getDiscountType,
                        LumiereCouponStrategy::getDiscountRate,
                        LumiereCouponStrategy::getDiscount,
                        LumiereCouponStrategy::getMin)
                .selectAs(LumiereCouponStrategy::getName,AdminRuleConfigCouponsVO::getStrategyName)
                .selectAs(LumiereCoupon::getName,AdminRuleConfigCouponsVO::getCouponName)
                .eq(LumiereCouponStrategy::getStatus,1)
                .eq(LumiereCouponStrategy::getCouponType,1)
                .leftJoin(LumiereCoupon.class,LumiereCoupon::getId,LumiereCouponStrategy::getCouponId)
                .orderByDesc(LumiereCouponStrategy::getAddTime));
        return ResponseUtil.ok(adminRuleConfigCouponsVOS);
    }

    public ResponseUtil.Response grantLogs(Long id, Integer limit, Integer page) {
        IPage<LumiereCouponGrantLog> couponGrantLogs = lumiereCouponGrantLogService.page(new Page<>(page,limit),Wrappers.lambdaQuery(LumiereCouponGrantLog.class)
                .eq(LumiereCouponGrantLog::getStrategyId, id)
                .orderByDesc(LumiereCouponGrantLog::getAddTime));
        List<LumiereCouponGrantLog> collect = couponGrantLogs.getRecords().stream().map(grant -> {
            LumiereCoupon coupon = lumiereCouponService.getById(grant.getCouponId());
            LitemallAdmin admin = litemallAdminService.findById(grant.getCreateId());
            grant.setCouponName(coupon.getName());
            grant.setCreateName(admin.getUsername());
            return grant;
        }).collect(Collectors.toList());
        couponGrantLogs.setRecords(collect);
        return ResponseUtil.okPage(couponGrantLogs);
    }
}
